package com.seckill.service.impl;

import com.seckill.common.error.BusinessException;
import com.seckill.common.error.ErrorEnum;
import com.seckill.common.model.ValidationResult;
import com.seckill.common.service.RedisService;
import com.seckill.dao.ItemDOMapper;
import com.seckill.dao.ItemStockDOMapper;
import com.seckill.dao.StockLogDOMapper;
import com.seckill.domain.ItemDO;
import com.seckill.domain.ItemStockDO;
import com.seckill.domain.StockLogDO;
import com.seckill.model.dto.ItemDTO;
import com.seckill.model.dto.PromoDTO;
import com.seckill.mq.MQProducer;
import com.seckill.service.ItemService;
import com.seckill.service.PromoService;
import com.seckill.util.ValidatorUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author lill
 * @date 2019-06-21
 */
@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private ItemDOMapper itemDOMapper;

    @Autowired
    private ItemStockDOMapper itemStockDOMapper;

    @Autowired
    private PromoService promoService;

    @Autowired
    private RedisService<ItemDTO> redisService;

    @Autowired
    private RedisService<Integer> integerRedisService;

    @Autowired
    private RedisService<String> stringRedisService;

    @Autowired
    private MQProducer mqProducer;

    @Autowired
    private StockLogDOMapper stockLogDOMapper;
    /**
     * 1表示还未开始，2表示进行中，3表示已结束
     */
    private static final int PROMO_NOT_STARTED = 1;
    private static final int PROMO_PROCESSING = 2;
    private static final int PROMO_OVER = 3;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ItemDTO createItem(ItemDTO itemDTO) {
        //校验入参
        ValidationResult result = ValidatorUtil.validate(itemDTO);
        if (result.isHasErrors()) {
            throw new BusinessException(ErrorEnum.VALIDATION_REQUEST_PARAM_ERROR, result.getErrMsg());
        }
        //转化 itemDTO 为 itemDO
        ItemDO itemDO = convertItemDOFromItemDTO(itemDTO);
        itemDOMapper.insertSelective(itemDO);
        itemDTO.setId(itemDO.getId());

        //转化 itemDTO 为 itemStockDO
        ItemStockDO itemStockDO = convertItemStockDOFromItemDTO(itemDTO);
        itemStockDOMapper.insertSelective(itemStockDO);

        //返回创建完成的对象，这里要返回存入数据库的对象
        return getItemById(itemDTO.getId());
    }

    private ItemDO convertItemDOFromItemDTO(ItemDTO itemDTO) {
        if (null == itemDTO) {
            return null;
        }
        ItemDO itemDO = new ItemDO();
        BeanUtils.copyProperties(itemDTO, itemDO);
        return itemDO;
    }

    private ItemStockDO convertItemStockDOFromItemDTO(ItemDTO itemDTO) {
        if (null == itemDTO) {
            return null;
        }
        ItemStockDO itemStockDO = new ItemStockDO();
        itemStockDO.setItemId(itemDTO.getId());
        itemStockDO.setStock(itemDTO.getStock());
        return itemStockDO;
    }

    @Override
    public List<ItemDTO> listItem() {
        List<ItemDO> itemDOList = itemDOMapper.listItem();

        List<ItemDTO> itemDTOList = itemDOList.stream().map(itemDO -> {
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
            ItemDTO itemDTO = this.convertModelFromDataObject(itemDO, itemStockDO);
            return itemDTO;
        }).collect(Collectors.toList());
        return itemDTOList;
    }

    @Override
    public ItemDTO getItemById(Integer id) {
        ItemDO itemDO = itemDOMapper.selectByPrimaryKey(id);
        if (null == itemDO) {
            return null;
        }
        // 操作获得库存数量
        ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());

        //转化 itemDO、itemStockDO 为 itemDTO
        ItemDTO itemDTO = convertModelFromDataObject(itemDO, itemStockDO);

        //获取商品秒杀活动信息
        PromoDTO promoDTO = promoService.getPromoByItemId(itemDTO.getId());
        if (null != promoDTO && promoDTO.getStatus().intValue() != PROMO_OVER) {
            itemDTO.setPromoDTO(promoDTO);
        }

        return itemDTO;
    }

    @Override
    public ItemDTO getItemByIdInCache(Integer id) {
        ItemDTO itemDTO = redisService.getCache("item_validate_" + id);
        if (null == itemDTO) {
            itemDTO = getItemById(id);
            redisService.setCache("item_validate_" + id, itemDTO, 10, TimeUnit.MINUTES);
        }
        return itemDTO;
    }

    private ItemDTO convertModelFromDataObject(ItemDO itemDO, ItemStockDO itemStockDO) {
        ItemDTO itemDTO = new ItemDTO();
        BeanUtils.copyProperties(itemDO, itemDTO);
        itemDTO.setStock(itemStockDO.getStock());
        return itemDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean decreaseStock(Integer itemId, Integer amount) {
        int result = integerRedisService.getCache("promo_item_stock_" + itemId) - amount;
        if (result > 0) {
            int total = integerRedisService.getCache("promo_item_stock_" + itemId) - amount;
            integerRedisService.setCache("promo_item_stock_" + itemId, total);
            return true;
        } else if (result == 0) {
            int total = integerRedisService.getCache("promo_item_stock_" + itemId) - amount;
            integerRedisService.setCache("promo_item_stock_" + itemId, total);
            // 设置库存不足
            integerRedisService.setCache("promo_item_stock_invalid_" + itemId, 0);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean asynchronousDecreaseStock(Integer itemId, Integer amount) {
        boolean mqResult = mqProducer.asyncReduceStock(itemId, amount);
        return mqResult;
    }

    @Override
    public void increaseDecreaseStock(Integer itemId, Integer amount) {
        int total = integerRedisService.getCache("promo_item_stock_" + itemId) + amount;
        integerRedisService.setCache("promo_item_stock_" + itemId, total);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void increaseSales(Integer itemId, Integer amount) {
        itemDOMapper.increaseSales(itemId, amount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String initStockLog(Integer itemId, Integer amount) {
        StockLogDO stockLogDO = new StockLogDO();
        stockLogDO.setItemId(itemId);
        stockLogDO.setAmount(amount);
        stockLogDO.setStockLogId(UUID.randomUUID().toString().replace("-", ""));
        stockLogDO.setStatus(1);
        stockLogDOMapper.insertSelective(stockLogDO);
        return stockLogDO.getStockLogId();

    }
}
